<template>
  <div id="conversation">
    <div class="header">
      <div class="avatar">
        <el-avatar
          size="large"
          src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
        ></el-avatar>
      </div>
      <span class="logo">
        <img alt="Tachikoma" :src="require('../assets/LOGO.png')" />
      </span>
    </div>
    <el-divider></el-divider>
    <div class="bubbleArea">
      <bubble
        v-for="item in bubbleList"
        :key="item.index"
        :content="item.bubbleContent"
        :self-active="item.selfActive"
        @click="onPlayer"
      />
      <div id="_end" style="height:0px; overflow:hidden"></div>
    </div>
    <div class="inputArea">
      <el-button
        icon="el-icon-microphone"
        type="primary"
        :loading="recorderStart"
        :class="{ onRecorder: recorderStart }"
        @click="onStartRecorder()"
        style="position:relation;float:left;margin-right:1vw"
        >语音</el-button
      >
      <div class="input">
        <el-input
          placeholder="请输入命令"
          v-model="input"
          clearable
          @keyup.enter.native="onSubmitInput"
        >
        </el-input>
      </div>
      <el-button
        type="success"
        icon="el-icon-position"
        circle
        style="position:relation;float:left;margin-left:2vw"
        @click="onSubmitInput"
      >
      </el-button>
    </div>
    <popup
      :dialog-visible="dialogVisibleWeather"
      :weather-data="actionParams"
      @func="getWeatherVisbleFlag"
      @weather="getWeatherData"
    />
    <mapPop
      :dialog-visible="dialogVisibleMap"
      :city="actionParams"
      @func="getMapVisbleFlag"
    />
    <audio ref="audio" controls style="display:none" v-if="reloadFlag" autoplay>
      <!-- <source src="../assets/audio/temp.mp3" type="audio/mpeg"> -->
      <source :src="reAudioSrc" type="audio/wav" />
      您的浏览器不支持 audio 元素。
    </audio>
  </div>
</template>

<script>
import Recorder from 'js-audio-recorder'
import qs from 'qs'
import Base64 from 'js-base64'
import popup from './message/insidePopup.vue'
import bubble from './message/bubble.vue'
import mapPop from './message/map.vue'

export default {
  name: 'conversation',
  components: {
    bubble,
    Recorder,
    qs,
    Base64,
    popup,
    mapPop
  },
  data () {
    return {
      input: '',
      bubbleList: [
        {
          selfActive: false,
          bubbleContent: 'Tachikma正在待命，文字输入或点击语音按钮唤醒Tachikma'
        },
        {
          selfActive: false,
          bubbleContent: '尝试问问：北京天气如何'
        }
      ],
      messageBuffer: '',
      PCMdata: null,
      WAVdata: null,
      baiduToken: null,
      recorderStart: false,
      recorder: null,
      redata: { result: [''] },
      blob2Base64Str: null,
      toAudioStr: '',
      reaudio: null,
      reAudioSrc: '',
      reloadFlag: true,
      contentDiv: '',
      sender: null,
      // dialogVisible: {
      //   weahter: false,
      //   map: false
      // },
      dialogVisibleWeather: false,
      dialogVisibleMap: false,
      actionParams: {
        intent: 'weather',
        city: '北京'
      }
    }
  },
  created: function () {
    this.getToken()
    function uuid () {
      function S4 () {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
      }

      return (
        S4() +
        S4() +
        '-' +
        S4() +
        '-' +
        S4() +
        '-' +
        S4() +
        '-' +
        S4() +
        S4() +
        S4()
      )
    }
    this.sender = uuid()
  },
  mounted: function () {
    this.contentDiv = document.getElementsByClassName('bubbleArea')
    console.log(this.contentDiv)
  },
  watch: {
    recorderStart: function (val) {
      if (val === true) {
        setTimeout(() => {
          this.onStopRecorder()
          this.recorderStart = false
          console.log(this.recorderStart)
          setTimeout(() => {
            this.onPostAudio()
          }, '200')
        }, '2000')
      }
    }
  },
  methods: {
    async onStartRecorder () {
      if (!this.recorderStart) {
        this.recorderStart = true
        console.log(this.recorderStart)
        if (!this.recorder) {
          this.recorder = new Recorder({
            sampleBits: 16, // 采样位数，支持 8 或 16，默认是16
            sampleRate: 16000, // 采样率，支持 11025、16000、22050、24000、44100、48000，根据浏览器默认值，我的chrome是48000
            numChannels: 1 // 声道，支持 1 或 2， 默认是1
          })
        }
        this.recorder.start().then(() => {
          console.log('start')
        })
      } else {
        this.recorderStart = false
      }
    },
    async onStopRecorder () {
      this.recorder.stop()
      console.log('stop')
      this.PCMdata = this.recorder.getPCMBlob()
      this.WAVdata = this.recorder.getWAVBlob()
      // this.recorder.downloadPCM('temp')
      // this.recorder.downloadWAV('temp')
      await this.blobToDataURI(this.PCMdata, result => {
        this.blob2Base64Str = result
        // console.log(this.blob2Base64Str)
      })
    },
    onPostAudio () {
      let data = {
        format: 'pcm',
        rate: 16000,
        dev_pid: 1537,
        channel: 1,
        token: this.baiduToken.access_token,
        cuid: 'baidu_workshop',
        len: this.PCMdata.size,
        speech: this.blob2Base64Str
      }
      console.log(this.baiduToken)
      // console.log(JSON.stringify(data))
      this.$axios
        .post('http://vop.baidu.com/server_api', JSON.stringify(data))
        .then(res => {
          if (res) {
            const result = res.data
            this.redata = result
            this.messageBuffer = result.result[0]
            console.log(result)
            // this.bubbleList.push({
            //   selfActive: true,
            //   bubbleContent: result.result[0]
            // })
            this.addBubble(true, result.result[0])
            this.contentDiv.scrollTop = this.contentDiv.scrollHeight
            this.postRasa()
            // 添加气泡消息
          }
        })
    },
    onPlayer: function () {
      if (this.recorder) {
        this.recorder.play()
      } else {
        alert('Data is NULL!')
      }
    },
    async blobToDataURI (blob, callback) {
      let reader = new FileReader()
      reader.onload = function (e) {
        callback(e.target.result.split('data:;base64,')[1])
      }
      reader.readAsDataURL(blob)
    },
    onStr2Audio () {
      let data = {
        appid: '24057848',
        apikey: 'ZCRueKzVcLw9ysOtlNQd7rf8',
        tex: this.toAudioStr,
        tok: this.baiduToken,
        cuid: 'baidu_workshop',
        ctp: 1,
        lan: 'zh',
        aue: 6
      }
      this.$axios
        .post('http://tsn.baidu.com/text2audio', qs.stringify(data), {
          responseType: 'blob' // 此处防止返回为其他编码，导致处理困难
        })
        .then(res => {
          if (res) {
            const result = res.data
            this.reaudio = result

            console.log(res)
            // 正在处理

            let src = URL.createObjectURL(result)
            console.log(src)
            this.reAudioSrc = src
            // this.$refs.audio.setAttribute('src', src)
            // this.$refs.audio.setAttribute('type', 'audio/wav')
            this.reloadOfPart()
          }
        })
    },
    reloadOfPart () {
      this.reloadFlag = false
      this.$nextTick(() => {
        this.reloadFlag = true
      })
    },
    async getToken () {
      this.baiduToken = this.$store.state.app.token
      console.log(await this.$store.state.app.token)
    },
    onSubmitInput () {
      // this.bubbleList.push({
      //   selfActive: true,
      //   bubbleContent: this.input
      // })
      this.addBubble(true, this.input)
      this.messageBuffer = this.input
      // this.contentDiv.scrollIntoView()
      this.postRasa()
      let temp = document.getElementsByClassName('bubbleArea')[0]
      setTimeout(() => {
        temp.scrollTop = temp.scrollHeight
        // console.log(temp.scrollHeight)
      }, 200)
    },
    postRasa () {
      const params = {
        sender: this.sender,
        message: this.messageBuffer
      }
      this.$axios
        .post(
          'http://localhost:5005/webhooks/rest/webhook',
          JSON.stringify(params)
        )
        .then(res => {
          this.input = ''
          let message = null
          if (res) {
            for (let i = 0; i < res.data.length; i++) {
              if (this.isJsonString(res.data[i].text)) {
                message = JSON.parse(res.data[i].text)
                this.actionExecute(message)
              } else {
                this.addBubble(false, res.data[i].text)
                this.toAudioStr = res.data[i].text
                this.onStr2Audio()
              }
            }
            let temp = document.getElementsByClassName('bubbleArea')[0]
            setTimeout(() => {
              temp.scrollTop = temp.scrollHeight
              console.log(temp.scrollHeight)
            }, 200)
          }
        })
    },
    // 动作执行
    actionExecute (actionObj) {
      if (actionObj.intent === 'weather') {
        this.showWeather(actionObj)
        console.log('weather running')
      } else if (actionObj.intent === 'open_app') {
        this.openAppDll(actionObj)
      } else if (actionObj.intent === 'search_map') {
        this.showAMap(actionObj)
      } else if (actionObj.intent === 'search') {
        this.showSearch(actionObj.info)
      }
    },
    showWeather (params) {
      this.actionParams = params
      this.dialogVisibleWeather = true
      console.log(this.dialogVisibleWeather)
      // 此处可根据指针焦点判断
      setTimeout(() => {
        this.dialogVisibleWeather = false
      }, '3000')
    },
    openAppDll (params) {
      console.log(params.app)
      let url =
        'G:\\Documents\\Tachikoma\\client-electron\\tckm-client/public/shell/'
      if (params.app === '浏览器') {
        this.unExec(url + 'chrome_start.bat')
      } else if (params.app === '网易云音乐') {
        this.unExec(url + 'wangyi_start.bat')
      }
      // this.unExec('chcp 65001')
      // this.unExec(url + 'chrome_start.bat')
    },
    unExec (name) {
      const exec = require('child_process').exec

      // 任何你期望执行的cmd命令，ls都可以
      let cmdStr = name
      // 执行cmd命令的目录，如果使用cd xx && 上面的命令，这种将会无法正常退出子进程
      let cmdPath = 'G:\\Documents\\Tachikoma\\client-electron\\tckm-client'

      // 执行命令行，如果命令不需要路径，或就是项目根目录，则不需要cwd参数：
      let workerProcess = exec(cmdStr, { cwd: cmdPath })
      // 不受child_process默认的缓冲区大小的使用方法，没参数也要写上{}：workerProcess = exec(cmdStr, {})

      // 打印正常的后台可执行程序输出
      workerProcess.stdout.on('data', function (data) {
        console.log('stdout: ' + data)
      })

      // 打印错误的后台可执行程序输出
      workerProcess.stderr.on('data', function (data) {
        console.log('stderr: ' + data)
      })

      // 退出之后的输出
      workerProcess.on('close', function (code) {
        console.log('out code：' + code)
      })
    },
    showAMap (params) {
      this.actionParams = params
      this.dialogVisibleMap = true
    },
    showSearch (params) {
      let url = 'https://aip.baidubce.com/rpc/2.0/kg/v1/cognitive/question?'
      let par = {
        access_token: this.baiduToken.access_token
        // charset: 'UTF-8'
      }
      let data = {
        query: this.messageBuffer
      }
      this.$axios.post(url + qs.stringify(par), data).then(res => {
        if (res) {
          let content = res.data.result[0].response.answer
          this.addBubble(false, content)
        }
      })
    },
    // --utils fuctions--
    addBubble (active, content) {
      this.bubbleList.push({
        selfActive: active,
        bubbleContent: content
      })
    },
    isJsonString (str) {
      try {
        if (typeof JSON.parse(str) === 'object') {
          return true
        }
      } catch (e) {}
      return false
    },
    getWeatherVisbleFlag (temp) {
      this.dialogVisibleWeather = temp
    },
    getMapVisbleFlag (temp) {
      this.dialogVisibleMap = temp
    },
    getWeatherData (temp) {
      if (this.dialogVisibleWeather === true) {
        let result =
          temp.city +
          '当前天气：' +
          temp.weather +
          '，气温：' +
          temp.temperature +
          '摄氏度'
        this.addBubble(false, result)
        this.toAudioStr = result
        this.onStr2Audio()
      }
    }
  }
}
</script>

<style lang="scss" scoped>
#conversation {
  width: 84vw;
  height: 100vh;
  position: absolute;
  right: 3vw;
}
.header {
  height: 10vh;
  .avatar {
    position: absolute;
    height: 8vh;
    width: 8vh;
    top: 3vh;
    .el-avatar {
      box-shadow: -1px 1px 1px #ccc;
    }
  }
  .logo {
    position: absolute;
    top: 3vh;
    left: 4vw;
    img {
      height: 8vh;
    }
  }
}
.bubbleArea {
  height: 65vh;
  overflow: auto;
}
.inputArea {
  border-top: 1px solid #dcdfe6;
  padding: 5vh;
  position: fixed;
  bottom: 0;
  background: #fff;
  // height: 10vh;
  z-index: 100;
  width: 84vw;
  .input {
    width: 50vw;
    position: relative;
    float: left;
    .el-input {
    }
    .el-input_inner {
      border-radius: 30px !important;
    }
  }
}
.onRecorder {
}
</style>
